package org.vison.wonfu.framework.soa;




import org.vison.wonfu.framework.commons.utils.CollectionUtils;
import org.vison.wonfu.framework.soa.annotation.SOAParamsMode;
import org.vison.wonfu.framework.soa.annotation.SOAResultMode;
import org.vison.wonfu.framework.soa.annotation.SoaRequestMethod;
import org.vison.wonfu.framework.soa.protocol.Protocol;

import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Stream;

/**
 * Invocation接口定义了RPC（远程过程调用）框架中调用相关的一系列操作和属性，
 * 它作为RPC框架中请求和响应的核心抽象，提供了获取和设置调用上下文信息的方法，
 * 包括调用者、调用模式、远程应用信息、服务接口名、方法名、参数、超时设置、附加属性等。
 */
public interface Invocation {

    Protocol getProtocol();

    boolean isHttps();

    void setHttps(boolean https);

    void setSoaRequestMethod(SoaRequestMethod soaRequestMethod);

    SoaRequestMethod getSoaRequestMethod();

    SOAParamsMode getParamsMode();

    void setParamsMode(SOAParamsMode paramsMode);

    SOAResultMode getResultMode();

    void setResultMode(SOAResultMode resultMode);

    boolean isCompleteResult();

    void setCompleteResult(boolean completeResult);

    /**
     * 原类型是 Map<String, Object>
     * @return
     */
    Map<String, Object> getFixedParams();

    String getMethodPath();

    String getServicePath();

    List<String> getParamsName();

    String getHost();

    void setHost(String host);

    int getPort();

    Map<String, String> getExtraHeader();
    void setExtraHeader(Map<String, String> extraHeader);


    /**
     * get the invoker in current context.
     */
    Invoker<?> getInvoker();

    void setInvoker(Invoker<?> invoker);

    InvokeMode getInvokeMode();

    void setInvokeMode(InvokeMode invokeMode);

    String getProtocolServiceKey();

    /**
     * get remote application name(app id)
     */
    String getRemoteApplication();

    /**
     * set remote application name(app id)
     */
    void setRemoteApplication(String remoteApplication);

    /**
     * get service CommandKey
     */
    String getCommandKey();

    Class<?> getFallback();

    /**
     * get service command key
     */
    String getServiceCommandKey();

    /**
     * get app command key
     */
    String getAppCommandKey();

    /**
     * get the interface name.
     */
    String getServiceName();

    /**
     * get version<br/>
     * <ul>
     *     <li>provider: service version</li>
     *     <li>consumer: remote ref service version</li>
     * </ul>
     */
    String getVersion();

    /**
     * get gray version
     */
    String getGrayVersion();

    /**
     * get method name.
     */
    String getMethodName();

    /**
     * get parameter types.
     */
    Class<?>[] getParameterTypes();

    /**
     * get parameter types desc.
     */
    String getParameterTypesDesc();

    /**
     * get parameter's signature, string representation of parameter types.
     *
     * @return parameter's signature
     * @see #getParameterTypes()
     */
    default String[] getCompatibleParamSignatures() {
        return Stream.of(getParameterTypes())
                .map(Class::getName)
                .toArray(String[]::new);
    }

    /**
     * get arguments.
     */
    Object[] getArguments();

    Class<?> getReturnType();

    Type[] getReturnTypes();

    void setTimeout(Integer timeout);

    Integer getTimeout();

    void setConnectionTimeout(Integer connectionTimeout);

    Integer getConnectionTimeout();

    Map<Object, Object> getAttributes();

    Object put(Object key, Object value);

    Object putIfAbsent(Object key, Object value);

    Object get(Object key);

    Object get(String key, Object defaultValue);

    /**
     * value instanceof String
     **/
    default String getString(String key) {
        return this.getString(key, null);
    }

    /**
     * value instanceof String
     **/
    String getString(String key, String defaultValue);

    Map<String, Object> getAttachments();

    Map<String, Object> getRawAttachments();

    default void putAttachment(String key, Object value) {
        getAttachments().put(key, value);
    }

    default void putAttachments(Map<String, Object> attachments) {
        if (CollectionUtils.isEmptyMap(attachments)) {
            return;
        }

        attachments.forEach(this::putAttachment);
    }

    default void putAttachmentIfAbsent(String key, Object value) {
        getAttachments().putIfAbsent(key, value);
    }

    default void putAttachmentsIfAbsent(Map<String, Object> attachments) {
        if (CollectionUtils.isEmptyMap(attachments)) {
            return;
        }

        attachments.forEach(this::putAttachmentIfAbsent);
    }

    void putRawAttachment(String key, Object value);

    default void putRawAttachments(Map<String, Object> rawAttachments) {
        if (CollectionUtils.isEmptyMap(rawAttachments)) {
            return;
        }
        rawAttachments.forEach(this::putRawAttachment);
    }

    void putRawAttachmentIfAbsent(String key, Object value);

    default void putRawAttachmentsIfAbsent(Map<String, Object> rawAttachments) {
        if (CollectionUtils.isEmptyMap(rawAttachments)) {
            return;
        }
        rawAttachments.forEach(this::putRawAttachmentIfAbsent);
    }

    default Object getAttachment(String key) {
        return getAttachments().get(key);
    }

    default Object getAttachment(String key, Object defaultValue) {
        return getAttachments().getOrDefault(key, defaultValue);
    }

    /**
     * value instanceof String
     **/
    default String getAttachmentString(String key) {
        return this.getAttachmentString(key, null);
    }

    /**
     * value instanceof String
     **/
    String getAttachmentString(String key, String defaultValue);

    default Object getRawAttachment(String key) {
        return getRawAttachment(key, null);
    }

    Object getRawAttachment(String key, Object defaultValue);

    /**
     * value instanceof String
     **/
    default String getRawAttachmentString(String key) {
        return this.getRawAttachmentString(key, null);
    }

    /**
     * value instanceof String
     **/
    String getRawAttachmentString(String key, String defaultValue);

    void putDMCLog(String key, ThrowableSupplier<Object> value, Level level);

    void putDMCLog(String key, Object value);

    Map<String, Object> getBaseMDCLogs();

    Map<String, Object> getLevelMDCLogs();

    /**
     * is provider side.
     *
     * @return provider side.
     */
    boolean isProviderSide();

    /**
     * is consumer side.
     *
     * @return consumer side.
     */
    boolean isConsumerSide();

}
